Getting started using analyzers
Premise
We assume the analyzers you want to use are distributed as a nuget package.
Using analyzers in a single project
Raw command line
A dotnet CLI tool, called fsharp-analyzers, is used to run analyzers outside the context of an IDE.
Add it to your tool-manifest with:
|
Next, add the PackageReference
pointing to your favorite analyzers to the .fsproj
file of the project you want to analyze:
|
At the time of writing, the G-Research analyzers package contains the only analyzers compatible with the latest CLI tool.
With the package downloaded, we can run the CLI tool:
|
Using an MSBuild target
As you can see, the path to the analyzer DLL files could be tricky to get right across a wide range of setups.
Luckily, we can use an MSBuild custom target to take care of the path construction.
Add FSharp.Analyzers.Build to your fsproj
:
|
This imports a new target to your project file: AnalyzeFSharpProject
.
And will allow us to easily run the analyzers for our project.
Before we can run dotnet msbuild /t:AnalyzeFSharpProject
, we need to specify our settings in a property called FSharpAnalyzersOtherFlags
:
|
To locate the analyzer DLLs in the filesystem, we use the variable $(PkgG-Research_FSharp_Analyzers)
. It's produced by NuGet and normalized to be usable by MSBuild.
In general, a Pkg
prefix is added and dots in the package ID are replaced by underscores. But make sure to look at the nuget.g.props file in the obj
folder for the exact string.
The /analyzers/dotnet/fs
subpath is a convention analyzer authors should follow when creating their packages.
At last, you can run the analyzer from the project folder:
|
Note: if your project has multiple TargetFrameworks
the tool will be invoked for each target framework.
Using analyzers in a solution
Adding the custom target from above to all .fsproj
files of a solution doesn't scale very well.
So we use the MSBuild infrastructure to add the needed package reference and the MSBuild target to all projects in one go.
We start with adding the PackageReference
pointing to your favorite analyzers to the Directory.Build.props file.
This adds the package reference to all .fsproj
files that are in a subfolder of the file location of Directory.Build.props
:
|
Likewise we add the FSharpAnalyzersOtherFlags
property to the Directory.Build.targets file.
This is effectively the same as adding a property to each *proj
file which exists in a subfolder.
|
⚠️ We are adding the FSharpAnalyzersOtherFlags
property to our Directory.Build.targets and not to any Directory.Build.props file!
MSBuild will first evaluate Directory.Build.props
which has no access to the generated nuget.g.props. $(PkgG-Research_FSharp_Analyzers)
won't be known at this point. Directory.Build.targets
is evaluated after the project file and has access to Pkg
generated properties.
All projects in the solution
We can run the AnalyzeFSharpProject
target against all projects in a solution
|
Select specific projects
As we don't want to target all projects in the solution, we create a second custom MSBuild target that calls the project-specific target for all relevant projects.
Add the following custom target to the Directory.Solution.targets file to be able to invoke analysis from all selected projects in one simple command:
|
At last, you can run the analyzer from the solution folder:
|
Note: we passed the --code-root
flag so that the *.sarif
report files will report file paths relative to this root. This can be imported for certain editors to function properly.
MSBuild tips and tricks
MSBuild can be overwhelming for the uninitiated. Here are some tricks we've seen in the wild:
Use well-known properties
Checkout the MSBuild reserved and well-known properties to use existing variables like $(MSBuildProjectFile)
.
Wrap path arguments in quotes
As MSBuild is all XML, you can use "
to wrap evaluated values in quotes:
|
Extend <FSharpAnalyzersOtherFlags>
in multiple lines
You can extend the value of $(FSharpAnalyzersOtherFlags)
by setting it again in multiple lines:
|
Verify parameters are present
It can be a bit confusing to find out if a variable contains the value you think it does. We often add a dummy target to a project to print out some values:
|
Run dotnet msbuild YourProject.fsproj /t:Dump
and verify that CodeRoot
has a value or not.